home *** CD-ROM | disk | FTP | other *** search
- unit RunCmd;
-
- {$ifdef Ver90} { Delphi 2.0x }
- {$define DelphiLessThan3}
- {$endif}
- {$ifdef Ver93} { C++ Builder 1.0x }
- {$define DelphiLessThan3}
- {$endif}
-
- interface
-
- type
- TWaitProc = procedure of object;
- TBeforeWaitProc = TWaitProc;
- TAfterWaitProc = TWaitProc;
-
- procedure RunCommand(const Cmd, Params: String;
- BeforeWait: TBeforeWaitProc;
- AfterWait: TAfterWaitProc);
- //Extended version of RunCommand which can handle file associations
- procedure RunCommandEx(const Cmd, Params: String;
- BeforeWait: TBeforeWaitProc;
- AfterWait: TAfterWaitProc);
-
- implementation
-
- uses
- SysUtils, Forms, ShellAPI, Windows;
-
- {$ifdef DelphiLessThan3}
- type
- EWin32Error = class(Exception)
- public
- ErrorCode: DWORD;
- end;
-
- procedure RaiseLastWin32Error;
- var
- LastError: DWORD;
- Error: EWin32Error;
- begin
- LastError := GetLastError;
- if LastError <> ERROR_SUCCESS then
- Error := EWin32Error.CreateFmt('Win32 Error. Code: %d.'#10'%s', [LastError, SysErrorMessage(LastError)])
- else
- Error := EWin32Error.Create('A Win32 API function failed');
- Error.ErrorCode := LastError;
- raise Error;
- end;
-
- function Win32Check(RetVal: BOOL): BOOL;
- begin
- if not RetVal then RaiseLastWin32Error;
- Result := RetVal;
- end;
- {$endif}
-
- procedure RunCommand(const Cmd, Params: String;
- BeforeWait: TBeforeWaitProc;
- AfterWait: TAfterWaitProc);
- var
- SI: TStartupInfo;
- PI: TProcessInformation;
- CmdLine: String;
- begin
- //Fill record with zero byte values
- FillChar(SI, SizeOf(SI), 0);
- //Set mandatory record field
- SI.cb := SizeOf(SI);
- //Ensure Windows mouse cursor reflects launch progress
- SI.dwFlags := StartF_ForceOnFeedback;
- //Set up command line
- CmdLine := Cmd;
- if Length(Params) > 0 then
- CmdLine := CmdLine + #32 + Params;
- //Try and launch child process. Raise exception on failure
- Win32Check(
- CreateProcess(
- nil, PChar(CmdLine), nil, nil, False, 0, nil, nil, SI, PI));
- try
- //Wait until process has started its main message loop
- WaitForInputIdle(PI.hProcess, Infinite);
- if Assigned(BeforeWait) then
- BeforeWait;
- WaitForSingleObject(PI.hProcess, Infinite);
- if Assigned(AfterWait) then
- AfterWait;
- finally
- //Close process and thread handles
- CloseHandle(PI.hThread);
- CloseHandle(PI.hProcess);
- end
- end;
-
- //Extended version of RunCommand which can handle file associations
- procedure RunCommandEx(const Cmd, Params: String;
- BeforeWait: TBeforeWaitProc;
- AfterWait: TAfterWaitProc);
- var
- SEI: TShellExecuteInfo;
- begin
- //Fill record with zero byte values
- FillChar(SEI, SizeOf(SEI), 0);
- //Set mandatory record field
- SEI.cbSize := SizeOf(SEI);
- //Ask for an open process handle and no message boxes
- SEI.fMask := see_Mask_NoCloseProcess or see_Mask_Flag_No_UI;
- //Tell API which window any possible error dialogs should be modal to
- SEI.Wnd := Application.Handle;
- //Set up command line
- SEI.lpFile := PChar(Cmd);
- if Length(Params) > 0 then
- SEI.lpParameters := PChar(Params);
- SEI.nShow := sw_ShowNormal;
- //Try and launch child process. Exit on failure
- Win32Check(ShellExecuteEx(@SEI));
- try
- //Wait until process has started its main message loop
- WaitForInputIdle(SEI.hProcess, Infinite);
- if Assigned(BeforeWait) then
- BeforeWait;
- WaitForSingleObject(SEI.hProcess, Infinite);
- if Assigned(AfterWait) then
- AfterWait;
- finally
- //Close process handle
- CloseHandle(SEI.hProcess);
- end
- end;
-
- end.
-